#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->setMaximumSize(206,280);
    this->setMinimumSize(206,280);

    this->setWindowTitle("计算器");

    QFont f("仿宋",14);  //字体对象
    ui->mainLineEdit->setFont(f);

    //在按钮上放图片
    QIcon con("E:\\QT_project\\temp\\calculator\\delete.png");
    ui->delButton->setIcon(con);

    //改变按钮背景色
    ui->equalButton->setStyleSheet("background:skyblue");
    ui->delButton->setStyleSheet("background:skyblue");
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_oneButton_clicked()
{
    expression += "1";
    ui->mainLineEdit->setText(expression);
}


void Widget::on_towButton_clicked()
{
    expression += "2";
    ui->mainLineEdit->setText(expression);
}


void Widget::on_threeButton_clicked()
{
    expression += "3";
    ui->mainLineEdit->setText(expression);
}


void Widget::on_fourButton_clicked()
{
    expression += "4";
    ui->mainLineEdit->setText(expression);
}


void Widget::on_fiveButton_clicked()
{
    expression += "5";
    ui->mainLineEdit->setText(expression);
}


void Widget::on_sixButton_clicked()
{
    expression += "6";
    ui->mainLineEdit->setText(expression);
}


void Widget::on_sevenButton_clicked()
{
    expression += "7";
    ui->mainLineEdit->setText(expression);
}


void Widget::on_eightButton_clicked()
{
    expression += "8";
    ui->mainLineEdit->setText(expression);
}


void Widget::on_nineButton_clicked()
{
    expression += "9";
    ui->mainLineEdit->setText(expression);
}


void Widget::on_addButton_clicked()
{
    expression += "+";
    ui->mainLineEdit->setText(expression);
}


void Widget::on_subButton_clicked()
{
    expression += "-";
    ui->mainLineEdit->setText(expression);
}


void Widget::on_mulButton_clicked()
{
    expression += "*";
    ui->mainLineEdit->setText(expression);
}


void Widget::on_divButton_clicked()
{
    expression += "/";
    ui->mainLineEdit->setText(expression);
}


void Widget::on_leftButton_clicked()
{
    expression += "(";
    ui->mainLineEdit->setText(expression);
}


void Widget::on_rightButton_clicked()
{
    expression += ")";
    ui->mainLineEdit->setText(expression);
}


void Widget::on_clearButton_clicked()
{
    expression.clear();
    ui->mainLineEdit->clear();
}


void Widget::on_delButton_clicked()
{
    expression.chop(1);
    ui->mainLineEdit->setText(expression);
}


#define my_MAX 100 // 调整栈的大小
struct stack_of_nums  // 用于存放数据的栈区
{
    float nums[my_MAX];
    int top; // 栈顶的下标
}bolannums;


struct stack_of_symbols // 用于存放不同运算符号的栈区
{
    char symbols[my_MAX];
    int top; // 栈顶下标
}bolansymbols;

void outpush(struct stack_of_nums*, struct stack_of_symbols*); // 使两个栈区出栈的函数


void Widget::on_equalButton_clicked()
{

    char opt[128] = {0};

    //把QString转换成char *
    QByteArray ba;
    ba.append(expression.toUtf8());    //把QString转换成QByteArray
    strcpy(opt,ba.data());    //data可以把QByteArry转换成const cahr *


    float num = 0; // 用于记录一行中读取到的一个数字
    int key = 2, index = 1;  // index为计算小数部分时，代表10的指数
    // key表示状态
    //2：num此时为0，未读取数据，此时为两个符号连续 如： （1 + 2） * 2
    //1：num此时已经读取过数据，且还在整数部分
    //0：num接下来要开始读取小数部分
    char c = 0; // 用于从输入中读取一个字符
    int j = 0;
    bolannums.top = bolansymbols.top = -1; // 先将栈顶初始化为-1，表示栈内无元素
    while ((c = opt[j]) != '\0') // scanf的正则表达式
    {
        j++;
        if (('0' <= c && c <= '9') && key) // 如果是数字则可以存入整数部分，key = 2 或者 1 的时候都可以进入整数的存储
        {
            key = 1;  // 一旦进入之后，赋值表示num已经读取到了数字
            num = num * 10 + c - '0'; // 将数字加到num中，连续读取数字的时候先 *10
        }
        else if (c == '.') // 遇到小数点的时候标志开始记录小数部分
            key = 0;
        else if ((c >= '0' && c <= '9') && key == 0)  // 小数部分的运算
        {
            num += (c - '0') * (float)pow(10, -(index++)); // 当前数字 * 0.1得到小数部分，并加入num
        }
        else if (c != ' ') // 不读取空格，只读取 + - * /
        {
            if (key != 2) // 在num被赋值过的时候才会加入栈nums， 同时表示读取数字直到遇到一个符号， 不包括换行
            {
                bolannums.nums[++bolannums.top] = num; // 移动栈顶指针并且加入栈区
                num = 0;
                index = 1;
                key = 2; // 将 num, index, key 初始化，方便下一次数据的读取
            }
            if (bolansymbols.top != -1) // 栈顶只有一个符号不需要outpush
            {
                if (c == '+' || c == '-') // 只要当栈顶元素优先级大于等于 C 的时候才会outpush
                    outpush(&bolannums, &bolansymbols);
                else if (c == ')')  // 当 c 为反括号的时候只需要outpush，但是 此时的 c 不需要入栈
                {
                    outpush(&bolannums, &bolansymbols);
                    if (bolansymbols.symbols[bolansymbols.top] == '(')
                        (bolansymbols.top)--;
                    continue; // 直接开始下次循环
                }
            }
            bolansymbols.symbols[++bolansymbols.top] = c; // c 入栈
        }
        else // 遇到空格直接开始下次循环 （可以不加此分支）
            continue;
    }
    if (key != 2)
        bolannums.nums[++bolannums.top] = num; // 如果式子最后以数字结尾则再次入栈
    if (bolansymbols.top != -1) // 判断符号栈区内是否为空，最后将所有栈区清空，只留下bolannums的第一个元素
        outpush(&bolannums, &bolansymbols);
    //printf("%.2f", bolannums.nums[0]);
    ui->mainLineEdit->setText(QString::number(bolannums.nums[0]));
    expression.clear();


}

void outpush(struct stack_of_nums* nums, struct stack_of_symbols* symbols)
{
    while (symbols->top != -1 && symbols->symbols[symbols->top] != '(') // 出栈，直到是遇见左括号或者栈内无元素
    {
        switch (symbols->symbols[symbols->top]) // 四则运算，每次运算会消耗掉栈顶元素，而每次出栈会,栈顶向下移动，相当于消耗掉了不会再次被使用
        {
        case '*':
            nums->nums[nums->top - 1] *= nums->nums[nums->top];
            break;
        case '/':
            nums->nums[nums->top - 1] /= nums->nums[nums->top];
            break;
        case '+':
            nums->nums[nums->top - 1] += nums->nums[nums->top];
            break;
        case '-':
            nums->nums[nums->top - 1] -= nums->nums[nums->top];
            break;
        }
        (nums->top)--, (symbols->top)--;
    }
}
